home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * Fast timers for Dynix.
- *
- *
- * Last modified: 6/16/89
- * by: sandstro
- * reason: added the equivalent of segvh()
- * to the mmap'd kernel code
- *
- * Last modified: 1/2/88
- * by: bnb
- * reason: add print function
- *
- * Last modified: 12/21/87
- * by: bnb
- * reason: add these comments
- *
- */
-
- #include <sys/param.h>
- #include <sys/file.h>
- #include <signal.h>
- #include <stddef.h>
- #include <sys/mman.h>
- #include <osfcn.h>
- #include <nlist.h>
- #include <stream.h>
- #include "presto.h"
- #include <time.h>
-
- extern void fatalerror();
- static void check_for_hole();
-
- static shared_t struct nlist Namelist[] = {
- { "_time" },
- #define X_TIME 0
- { "" }
- };
-
- #define VMUNIX "/dynix"
- #define KMEM "/dev/kmem"
-
- shared_t Spinlock timer_lock;
- shared_t Spinlock *t_lock = &timer_lock;
- private_t int t_kmemfd = -1;
-
- shared_t struct timeval *t_tv = 0;
- shared_t int t_tv_all_valid = 0; // valid in all address spaces
- private_t int t_tv_im_valid = 0; // valid in this address space
-
- shared_t int t_refcnt = 0;
- shared_t unsigned long timer_offt;
- shared_t int timer_pgsz;
- shared_t caddr_t timer_base;
-
- //
- // Always succeed, even if we can't map
- //
-
- void
- Timer::init()
- {
- t_lock->lock();
-
- t_refcnt++;
-
- if (t_tv) {
- // At least one address space has already
- // initialized this timer.
- t_starttime = getabsolutetime();
- t_lock->unlock();
- return;
- }
-
- //
- // ELSE, must map kernel time var into our address space
- //
-
- if (nlist(VMUNIX, Namelist) < 0) {
- perror("Cant get namelist");
- goto out;
- }
-
- if (Namelist[X_TIME].n_type == 0) {
- cerr << "Help... namelist is insane\n";
- goto out;
- }
-
- t_kmemfd = open(KMEM, O_RDONLY, 0);
- if (t_kmemfd < 0) {
- perror("open");
- cerr << "Can't open kmem for time class\n";
- goto out;
- }
-
- if (lseek(t_kmemfd, (long)Namelist[X_TIME].n_value, 0) < 0) {
- perror("lseek");
- cerr << "Can't lseek kmem for time class\n";
- goto out;
- }
-
- timer_pgsz = getpagesize();
- timer_offt = Namelist[X_TIME].n_value & ~(timer_pgsz-1);
- timer_base = grab_nonmalloc_hunk (timer_pgsz);
- if (timer_base == (char *) -1) {
- perror ("shbrk");
- error ("Shbrk failed in Timer init");
- goto out;
- }
- if (::mmap(timer_base, timer_pgsz, PROT_READ, MAP_SHARED,t_kmemfd, timer_offt) < 0) {
- perror("mmap");
- error("Can't map kmem first time");
- goto out;
- }
-
- t_tv = (struct timeval*)(timer_base + Namelist[X_TIME].n_value - timer_offt);
- t_tv_im_valid = 1;
- t_starttime = getabsolutetime();
- t_lock->unlock();
- return;
-
- out:
- if (t_tv == 0) {
- t_tv = new timeval; // static tv for ::gettimeofday
- t_tv_all_valid = 1;
- }
- close(t_kmemfd);
- t_kmemfd = -1; // must use system call
- t_lock->unlock();
- return;
-
- }
-
- Timer::~Timer()
- {
-
- t_lock->lock();
-
- #ifdef SANITY
- if (t_refcnt <= 0) {
- cerr << "Warning:non-positive refcnt on time destructor\n";
- }
- #endif
-
- t_refcnt--;
- if (t_refcnt == 0) {
- if (t_kmemfd < 0) {
- t_tv_all_valid = 0;
- delete t_tv;
- } else {
- close(t_kmemfd);
- t_tv = 0;
- t_kmemfd = -1;
- }
- t_lock->unlock();
- delete t_lock;
- } else
- t_lock->unlock();
- }
-
- double
- Timer::getabsolutetime()
- {
- check_for_hole();
- return (double)t_tv->tv_sec +
- ((double)(t_tv->tv_usec) * 1.0e-6);
- }
-
- char*
- Timer::getasciitime()
- {
- check_for_hole();
- return ctime((long*)&t_tv->tv_sec);
- }
-
- /*
- struct timeval*
- Timer::gettimeofday()
- {
- check_for_hole();
- if (t_kmemfd < 0) { // couldn't map
- ::gettimeofday(t_tv,0);
- }
- return t_tv;
- }
- */
- void
- Timer::print(ostream& s)
- {
- check_for_hole();
- s << form("(Timer)this= 0x%x,", this) <<
- "t_lock= " << t_lock << "\n";
- s << "t_tv= " << t_tv->tv_sec << ":" << t_tv->tv_usec << "\n";
- s << "t_refcnt=" << t_refcnt << ", t_starttime = " << t_starttime;
- }
-
- // The following routine, check_for_hole(), allows several address spaces
- // to check at the last minute whether they have memory mapped /dev/kmem,
- // and to map it if necessary. Sequent offers something similar for
- // shbrk(), called segvh(). Segvh() is discussed in section 5.2 of
- // ``A Parallel Programming Process Model'' by Beck and Olien,
- // a paper distributed at the 1988 SURF in Newport Beach, CA.
- // Segvh() doesn't work here, because segvh() assumes that you
- // want to map the file descriptor _shm_fd to your address space.
-
- static void check_for_hole()
- {
- // This routine assumes that Timer::init() has been called.
- if (t_tv_all_valid == 0) {
- // At least one routine succeeded in mmapping the kernel,
- // and no processes have yet tried and failed.
- if (t_tv_im_valid == 0) {
- // It wasn't us that succeeded in mmapping the kernel.
- t_kmemfd = open (KMEM, O_RDONLY, 0);
- if (t_kmemfd < 0) {
- perror ("open");
- error ("open kmem for Timer");
- }
- if (lseek (t_kmemfd, (long)Namelist[X_TIME].n_value, 0) < 0) {
- perror ("lseek");
- error ("lseek kmem for Timer");
- }
- if (::mmap(timer_base, timer_pgsz, PROT_READ, MAP_SHARED,
- t_kmemfd, timer_offt) < 0) {
- perror ("mmap");
- error ("mmap kmem for Timer");
- }
- }
- }
- }
-
-
-